/*
 * Copyright (c) United Binary LLC.  All rights reserved.
 * 
 * This code is licensed under the MIT License
 * 
 * SEE: http://harnessit.codeplex.com/license
 * 
 */
#region using ...
using System;
using System.Xml;
using System.Diagnostics;
using System.Collections;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
#endregion

namespace UnitedBinary.HarnessIt
{
	/// <summary>
	/// Summary description for TestProjectConfig.
	/// </summary>
	[Serializable]
	internal class TestProjectConfig
	{
		#region Member Variables
		private ArrayList nodes = new ArrayList();
		#endregion

		#region Construction
		internal TestProjectConfig()
		{
		}
		#endregion

		#region Node Manipulation Code
		internal bool GetState(string nodePath)
		{
			return GetNode(nodePath).Enabled;
		}

		internal void SetState(bool state, string nodePath)
		{
			GetNode(nodePath).Enabled = state;
		}

		internal bool ContainsNode(string nodePath)
		{
			int len = this.Nodes.Length;
			for (int i=0; i<len; i++)
			{
				if (Nodes[i].NodePath == nodePath)
				{
					return true;
				}
			}
			return false;
		}

		internal TestProjectNode GetNode(string nodePath)
		{
			int len = this.Nodes.Length;
			for (int i=0; i<len; i++)
			{
				if (Nodes[i].NodePath == nodePath)
				{
					return Nodes[i];
				}
			}

			throw new ArgumentException("Node '"+nodePath+"' not found.","nodePath");
		}

		internal void AddNode(TestProjectNode n)
		{
			nodes.Add(n);
		}

		internal void AddNode(string nodePath, bool state)
		{
			AddNode(new TestProjectNode(nodePath,state));
		}

		internal TestProjectNode [] Nodes
		{
			get
			{
				TestProjectNode [] retNodes = new TestProjectNode [nodes.Count];
				for(int i=0; i<nodes.Count; i++)
				{
					retNodes[i] = (TestProjectNode)nodes[i];
				}
				return retNodes;
			}
		}

		internal void ClearNodes()
		{
			nodes.Clear();
		}
		#endregion

		#region File IO
		internal void Save(string file)
		{
			XmlTextWriter tw = new XmlTextWriter(file, null);
			tw.Formatting = Formatting.Indented;
			try
			{
				//
				// Initialize our DOM and get access to the root <project_config> node.
				//
				XmlDocument dom = new XmlDocument();
				dom.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?><ProjectConfig />");
				XmlNodeList list = dom.GetElementsByTagName("ProjectConfig");
				XmlNode projCfgElt = list[0];

				//
				// Create the top level nodes and add them to the root.
				//
				XmlElement nodesElt = dom.CreateElement("Nodes");
				XmlElement fileElt = dom.CreateElement("File");

				projCfgElt.AppendChild(fileElt);
				projCfgElt.AppendChild(nodesElt);


				//
				// Set the file version property. 1.0 for now.
				//
				XmlElement versionElt = dom.CreateElement("Version");
				versionElt.InnerText = "1.0";
				fileElt.AppendChild(versionElt);

				//
				// Write the nodes into the <Nodes> node.
				//
				foreach(TestProjectNode n in nodes)
				{
					XmlElement nElt = dom.CreateElement("Node");
					XmlElement nPathElt = dom.CreateElement("Path");
					XmlElement nActiveElt = dom.CreateElement("Active");
					
					nElt.AppendChild(nActiveElt);
					nElt.AppendChild(nPathElt);

					nActiveElt.InnerText = n.Enabled.ToString();
					nPathElt.InnerText = n.NodePath;

					nodesElt.AppendChild(nElt);
				}

				//
				// Save the DOM to our file.
				//
				dom.WriteContentTo(tw);
			}
			finally
			{
				//
				// Close up our file handles (can't count on the GC).
				//
				if (tw != null)
				{
					tw.Flush();
					tw.Close();
				}
			}
		}

		internal void Load(string file)
		{
			FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
			try
			{
				//
				// Create an XML document to read and parse the XML project file.
				//
				XmlDocument dom = new XmlDocument();
				dom.Load(fs);

				//
				// Get and validate the file version.
				//
				XmlNodeList fileList = dom.GetElementsByTagName("File");
				if (fileList.Count!= 1)
				{
					System.IO.FileLoadException e = new System.IO.FileLoadException(
						"Invalid file format. Could not access the file settings in project config file.",
						file);
					throw e;
				}

				//
				// Search through the <file> node to get the file version. 
				// 
				bool versionFound = false;
				string version = "0.0";
				foreach(XmlNode n in fileList[0].ChildNodes)
				{
					if (n.Name == "Version")
					{
						versionFound = true;
						version = n.InnerText;
					}
				}

				if (!versionFound)
				{
					System.IO.FileLoadException e = new System.IO.FileLoadException(
						"Invalid file format. Could not access the file version in project config file.",
						file);
					throw e;
				}

				//
				// Get access to the <Nodes> node.
				//
				XmlNodeList xmlNodes = dom.GetElementsByTagName("Nodes");
				if (xmlNodes == null || xmlNodes.Count != 1)
				{
					System.IO.FileLoadException e = new System.IO.FileLoadException(
						"Invalid file format. Could not access the Nodes list in project config file.",
						file);
					throw e;
				}
				
				XmlNode nNode = xmlNodes[0];

				// If there are no config nodes, we're done here.
				int count = nNode.ChildNodes.Count;
				if (count <= 0)
				{
					return;
				}

				//
				// Read in each node name and store it in our array.
				//
				bool pathFound, activeFound;
				for (int i=0; i < count; i++)
				{
					TestProjectNode tpn = new TestProjectNode();
					XmlNode xmlNode = nNode.ChildNodes[i];

					pathFound = false;
					activeFound = false;

					foreach(XmlNode n in xmlNode.ChildNodes)
					{
						if (n.Name == "Active")
						{
							activeFound = true;
							tpn.Enabled = Convert.ToBoolean(n.InnerText);
						}
						else if (n.Name == "Path")
						{
							pathFound = true;
							tpn.NodePath = n.InnerText;
						}
					}

					if (pathFound == false)
					{
						System.IO.FileLoadException e = new System.IO.FileLoadException(
							"Invalid file format. Could not access the Path setting in project config file (Nodes element " + (i+1) + ").",
							file);
						throw e;
					}

					if (activeFound == false)
					{
						System.IO.FileLoadException e = new System.IO.FileLoadException(
							"Invalid file format. Could not access the Active setting in project config file (Nodes element " + (i+1) + ").",
							file);
						throw e;
					}

					nodes.Add(tpn);
				}
			}
			finally
			{
				// Close up our file handles (can't count on the GC).
				if (fs != null)
				{
					fs.Flush();
					fs.Close();
				}
			}
		}

//		private void UpdateParentsActiveState()
//		{
//			foreach(TestProjectNode tpn in nodes)
//			{
//				if (tpn.Enabled)
//				{
//					string path = tpn.NodePath;
//					int index = path.LastIndexOf('\\');
//					if (index > 0)
//					{
//						path = path.Substring(0, index - 1);
//						this.GetNode(path).Enabled = true;
//					}
//				}
//			}
//		}
		#endregion
	}
}
